package topt_12z.general;

import java.util.HashMap;
import java.util.Random;
import java.util.logging.Logger;

import topt_12z.interfaces.PacketListenerInterface;
import topt_12z.interfaces.SynchronizeEventInterface;
import topt_12z.logging.IO;
import topt_12z.network.PacketEvent;
import topt_12z.network.RoutingAgent;

/**
 * 
 * @author WrRaThY Singleton class that allows generating eventsssss
 */
public class EventGenerator implements SynchronizeEventInterface {
	private IO io;
	private Long idCounter = 0L;

	private static EventGenerator instance;
	private NetworkSynchronizer networkSynchronizer = null;
	private Random randomGenerator = new Random();
	private RoutingAgent routingAgent = null;

	private HashMap<String, PacketListenerInterface> packetListenersList = new HashMap<String, PacketListenerInterface>();
	private Logger log;

	private EventGenerator() {
		// empty private constructor
	}

	public synchronized static EventGenerator getInstance() {
		if (instance == null) {
			instance = new EventGenerator();
		}
		return instance;
	}

	/**
	 * inicjalizuje generator, wczytuje dane z pliku konfiguracyjnego etc
	 */
	public void init() {
		try {
			io = IO.getInstance();
			networkSynchronizer = NetworkSynchronizer.getInstance();
			log = io.getLogger();
			routingAgent = RoutingAgent.getInstance();
			routingAgent.setNetworkGrid(networkSynchronizer.getNetworkGrid());
			log.fine("EventGenerator init");
		} catch (Exception e) {
			System.out.println("Event generator initialization error!"
					+ e.getMessage());
		}

	}
	
	public void reset(){
		if(routingAgent!= null) routingAgent.reset();
		if(io!= null) io.reset();
		instance = null;
	}

	@Override
	public void handleSynchronizeEvent() {
		log.fine("Entering");
		// TODO wygeneruj odpowiednia ilosc pakietow i rozeslij informacje o
		// nich do odpowiednich nodow

		for (int i = 0; i < Globals.PACKETS_PER_SEC; i++) {
			PacketEvent newEvent = generatePacket();
			int fromCol = 0;
			int fromRow = 0;

			do {// inny adres pocztkowy niz koncowy
				fromCol = randomGenerator.nextInt(Globals.NETWORK_SIZE);
				fromRow = randomGenerator.nextInt(Globals.NETWORK_SIZE);
			} while (fromCol == newEvent.getDestAddressCol()
					&& fromRow == newEvent.getDestAddressRow());

			newEvent.setFromAddressCol(fromCol);
			newEvent.setFromAddressRow(fromRow);
			
			switch (Globals.ROUTING) {
			case Globals.ROUTING_LOSOWY:
				//nic
				break;
				
			case Globals.ROUTING_MAX:
				newEvent.setGeneratedRoute(routingAgent.maxRouting(fromRow, fromCol, newEvent.getDestAddressRow(), newEvent.getDestAddressCol()));
				break;
				
			case Globals.ROUTING_MIN:
				newEvent.setGeneratedRoute(routingAgent.minRouting(fromRow, fromCol, newEvent.getDestAddressRow(), newEvent.getDestAddressCol()));
				break;

			default:
				//nic
				break;
			}
			
			packetListenersList.get(fromRow+","+fromCol).handleMyEvent(newEvent);
		}

	}

	/**
	 * generuje Event
	 * 
	 * @return PacketEvent
	 */
	public PacketEvent generatePacket() {

		PacketEvent event = new PacketEvent(this);

		event.setStartTime(networkSynchronizer.getCurrentTime());

		event.setID(idCounter++);

		int toCol = randomGenerator.nextInt(Globals.NETWORK_SIZE - 1);
		int toRow = randomGenerator.nextInt(Globals.NETWORK_SIZE - 1);

		event.setDestAddressCol(toCol);
		event.setDestAddressRow(toRow);

		log.finest("event generated: " + event.toString());
		return event;
	}

	/**
	 * generuje Event
	 * 
	 * @return PacketEvent
	 */
	public PacketEvent generateStartEventTest(Integer start) {

		PacketEvent event = new PacketEvent(this);

		event.setStartTime(start);

		event.setID(idCounter++);

		log.finest("event generated: " + event.toString());
		return event;
	}

	public synchronized void addPacketListener(String key,PacketListenerInterface listener) {
		packetListenersList.put(key, listener);
	}

	public synchronized void removePacketListener(PacketListenerInterface listener) {
		packetListenersList.remove(listener);
	}

	public HashMap<String, PacketListenerInterface> getPacketListeners() {
		return packetListenersList;
	}
	
	@Override
	public String toString() {
		return "Event generator";
	}

}
